from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *

# import time

# from common.libs.ComDeal import WATER_CMD
from common.libs.Log import logging
from common.libs.MathFunc import MathFunc

from widgets.serial.ComSetWidget import ComSetWidget
from widgets.serial.Serial import Serial
from widgets.repeat.RepeatMeasureDialog import RepeatMeasureDialog
from widgets.environment.EnvironmentMeasureDialog import EnvironmentMeasureDialog
from widgets.base.BaseSetDialog import BaseSetDialog
from widgets.motor.MotorControlDialog import MotorControlDialog, MoveShowDock
from widgets.project.ProjectManager import ProjectCreateDialog, ProjectDock
from widgets.project.TaskRunManager import TaskRunManager

from widgets.app.DataTabView import DataTabView
from widgets.app.GraphWidget import GraphWidget


from ui.main import Ui_MainWindow
from ui import images


class MainWindow(QMainWindow, Ui_MainWindow):
    signal_moveDockLoadTask = pyqtSignal(dict)
    signal_moveDockUpatePos = pyqtSignal(str, str, str)
    signalTunnel = pyqtSignal(list, list, list)

    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)
        self.setupUi(self)
        self.setWindowState(Qt.WindowMaximized)
        self.setWindowIcon(QIcon(':icons/images_rc/app.png'))
        self.setWindowTitle("三维射束分析仪软件-RG202")
        # 窗口初始化
        self.widgetsInit()
        # Act动作初始化
        self.actInit()
        # 菜单栏初始化
        self.menuInit()
        # 工具栏初始化
        self.toolBarInit()
        # 信号绑定
        self.singalInit()

    def widgetsInit(self):
        # 串口配置
        self.comSetWidget = ComSetWidget()
        # 串口
        self.serial = Serial()
        # 基本设置
        self.baseSetDialog = BaseSetDialog()
        # 重复性测量
        self.repeatMeasureDialog = RepeatMeasureDialog()
        # 本底测量
        self.environmentMeasureDialog = EnvironmentMeasureDialog()
        # 电机移动
        self.motorControlDialog = MotorControlDialog()
        # 移动坐标窗口
        self.moveShowDock = MoveShowDock(self)
        # 项目窗口
        self.projectCreateDialog = ProjectCreateDialog()
        self.projectDock = ProjectDock(self)
        self.addDockWidget(Qt.LeftDockWidgetArea, self.projectDock)
        self.addDockWidget(Qt.LeftDockWidgetArea, self.moveShowDock)
        # self.projectDock.treeWidget.signalClickTask.connect(self.move_dock.rayGL.load_config)
        # 曲线显示窗口
        self.graph = GraphWidget()
        self.dataTab = DataTabView()
        self.verticalLayout_chart.addWidget(self.graph)
        self.verticalLayout_data_table.addWidget(self.dataTab)
        # 任务管理
        self.taskManager = TaskRunManager()

    def actInit(self):
        self.comSetAct = QAction(
            "&通信串口", self, triggered=self.comSetWidget.show)
        self.readInfoAct = QAction(QIcon(
            ':icons/images_rc/info.png'), '&读取信息', self, triggered=self.baseSetDialog.cmdReadInfo)
        self.environmentAct = QAction(QIcon(
            ':icons/images_rc/box.png'), '&本底测量', self, triggered=self.environmentMeasureDialog.exec)
        self.repeatMeasureAct = QAction(QIcon(
            ':icons/images_rc/repeat.png'), '&重复性', self, triggered=self.repeatMeasureDialog.exec)
        self.newProjectAct = QAction(QIcon(':icons/images_rc/file.png'),
                                     "&新建项目", self, triggered=self.projectDock.treeWidget.newProject)
        self.openProjectAct = QAction(QIcon(':icons/images_rc/open.png'),
                                      "&打开项目", self, triggered=self.projectDock.treeWidget.openProject)
        self.closeProjectAct = QAction(QIcon(
            ':icons/images_rc/close.png'), "&关闭项目", self, triggered=self.projectDock.treeWidget.closeProject)
        self.addPddTaskAct = QAction(QIcon(
            ':icons/images_rc/pdd.png'), "&添加PDD任务", triggered=self.projectDock.treeWidget.addPddTask)
        self.addOarTaskAct = QAction(QIcon(
            ':icons/images_rc/oar.png'), "&添加OAR任务", triggered=self.projectDock.treeWidget.addOarTask)
        self.baseSetAct = QAction(QIcon(
            ':icons/images_rc/move.png'), "&移动和测量设置", self, triggered=self.baseSetDialog.exec)
        self.motorControlAct = QAction(QIcon(
            ':icons/images_rc/move.png'), "&电机操作", triggered=self.motorControlDialog.exec)
        # self.startTaskAct = QAction(QIcon(':icons/images_rc/start.png'),'&开始执行', self, triggered=self.startMove)
        # self.stopTaskAct = QAction(QIcon(':icons/images_rc/stop.png'),'&暂停任务', self, triggered=self.pauseMove)
        # 视图
        self.projDockShowAct = QAction(QIcon(
            ':icons/images_rc/project.png'), "&项目管理窗口", triggered=self.projectDock.show)
        self.moveDockShowAct = QAction(
            QIcon(':icons/images_rc/move.png'), "&移动显示窗口", triggered=self.moveShowDock.show)
        # 任务执行
        self.stopTaskAct = QAction(QIcon(
            ':icons/images_rc/stop.png'), '&暂停任务', self, triggered=self.taskManager.stopMove)
        self.startTaskAct = QAction(QIcon(':icons/images_rc/start.png'), '&开始执行', self,
                                    triggered=lambda: self.taskManager.startMove(self.projectDock.treeWidget.getSelectTasks()))

    def menuInit(self):
        self.fileMenu = self.menuBar().addMenu("&文件")
        self.fileMenu.addAction(self.newProjectAct)
        self.fileMenu.addAction(self.openProjectAct)
        self.fileMenu.addAction(self.closeProjectAct)
        self.viewMenu = self.menuBar().addMenu("&视图")
        self.viewMenu.addAction(self.projDockShowAct)
        self.viewMenu.addAction(self.moveDockShowAct)
        self.setMenu = self.menuBar().addMenu("&设置")
        self.setMenu.addAction(self.baseSetAct)
        self.setMenu.addAction(self.comSetAct)

    def toolBarInit(self):
        """ 工具栏初始化 """
        # 创建工具栏
        self.toolbar = self.addToolBar('工具栏')
        # 设置工具栏显示文字说明
        self.toolbar.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
        self.toolbar.addWidget(self.serial.label_comStatus)
        self.toolbar.addAction(self.comSetAct)
        self.toolbar.addSeparator()
        self.toolbar.addAction(self.readInfoAct)
        self.toolbar.addAction(self.motorControlAct)
        self.toolbar.addSeparator()
        self.toolbar.addAction(self.environmentAct)
        self.toolbar.addSeparator()
        self.toolbar.addAction(self.repeatMeasureAct)
        self.toolbar.addSeparator()
        self.toolbar.addAction(self.newProjectAct)
        self.toolbar.addAction(self.openProjectAct)
        self.toolbar.addAction(self.closeProjectAct)
        self.toolbar.addAction(self.addPddTaskAct)
        self.toolbar.addAction(self.addOarTaskAct)
        self.toolbar.addSeparator()
        self.toolbar.addAction(self.startTaskAct)
        self.toolbar.addAction(self.stopTaskAct)

    def singalInit(self):
        """信号绑定"""
        # 串口信号
        self.serial.signal_open_ok.connect(self.baseSetDialog.cmdReadInfo)
        self.serial.signal_cmd.connect(self.signalSerialCmd)
        # 重复性测量
        self.repeatMeasureDialog.signal_serial_send.connect(self.serial.write)
        # 本底测量
        self.environmentMeasureDialog.signal_serial_send.connect(
            self.serial.write)
        # 配置参数更新
        self.baseSetDialog.signal_serial_send.connect(self.serial.write)
        self.baseSetDialog.signal_update.connect(self.updateConfig)
        # 电机移动
        self.motorControlDialog.signal_serial_send.connect(self.serial.write)
        self.motorControlDialog.signal_update_pos.connect(
            self.moveShowDock.updatePos)
        # self.moveShowDock.updatePos(x,y,z)
        # self.motorControlDialog.signal_task.connect(self.signalMotorTask)
        # 3D移动视图
        self.signal_moveDockLoadTask.connect(
            self.moveShowDock.rayGL.load_config)
        self.signal_moveDockUpatePos.connect(self.moveShowDock.updatePos)
        # 测量曲线
        self.signalTunnel.connect(self.graph.draw_two)
        # 任务信号
        self.taskManager.signal.connect(self.signalTaskManager)

    def updateConfig(self):
        # 更新重新性里面的刻度参数
        self.repeatMeasureDialog.scale_k = self.baseSetDialog.scale_k
        self.repeatMeasureDialog.scale_b = self.baseSetDialog.scale_b
        self.repeatMeasureDialog.scale_k_2 = self.baseSetDialog.scale_k_2
        self.repeatMeasureDialog.scale_b_2 = self.baseSetDialog.scale_b_2
        # 更新电机参数
        self.motorControlDialog.pulse_x = 100 # self.baseSetDialog.pulse
        self.motorControlDialog.pulse_y = 100 # self.baseSetDialog.pulse
        self.motorControlDialog.pulse_z = 100 # self.baseSetDialog.pulse
        self.motorControlDialog.updatePos(
            self.baseSetDialog.axis_x, self.baseSetDialog.axis_y, self.baseSetDialog.axis_z)
        # self.moveShowDock.updatePos(self.baseSetDialog.axis_x, self.baseSetDialog.axis_y, self.baseSetDialog.axis_z)

    def signalSerialCmd(self, cmd, data):
        """ signal 串口接收 """
        logging.info("收到命令：%s 数据：%s" % (cmd, data))
        if self.taskManager.flag:
            logging.info("[执行任务]")
            if cmd == '51':
                logging.info("走位中...")
                if data == 'FF':  # 移动完成
                    if self.taskManager.run_step == "start":  # 走到起点，执行任务
                        self.taskManager.processMove()
                    else:  # 回到原点
                        self.taskManager.clearFlag()
                        self.motorControlDialog.serial_deal(cmd, data)
                else:
                    self.motorControlDialog.serial_deal(cmd, data)
            if cmd == '50':  # 移动测量
                if data == 'FF':  # 走步任务完成
                    logging.info("移动测量完成")
                else:
                    self.motorControlDialog.serial_deal(cmd, data)
                    self.taskData(data[-16:])
            if cmd == '54':  # 紧急停止
                self.motorControlDialog.serial_deal(cmd, data)
                self.taskStop()
            if cmd == '5A':  # 任务执行完成
                self.taskDone()
            return
        if cmd == '51' or cmd == "50" or cmd == "44" or cmd == "54" or cmd == "55":
            self.motorControlDialog.serial_deal(cmd, data)
        if cmd == '71' or cmd == '73' or cmd == '41':  # 重复性测量
            logging.info('命令类型: 重复性测量')
            pos = [0, 0, 0]
            self.repeatMeasureDialog.serial_deal(cmd, data, pos)
            return
        if cmd == '72':  # 本底测量
            logging.info('命令类型: 本底测量')
            self.environmentMeasureDialog.serial_deal(cmd, data)
            return
        if cmd == '42' or cmd == '43' or cmd == '82':
            logging.info('命令类型: 基本配置')
            self.baseSetDialog.serial_deal(cmd, data)
            return

    def signalTaskManager(self, msg):
        if msg == "start":  # 执行当前任务
            logging.info("任务开始...")
            # 清除表格数据
            self.dataTab.clear_data()
            # 清除曲线数据
            self.graph.clear_data()
            # 获取任务信息
            t = self.taskManager.task_current
            # 曲线固定x轴范围
            self.graph.setAxisRange(t)
            # 电机移动到起点
            self.motorControlDialog.cmdMoveAxisPos(
                t['road'][0][0], t['road'][0][1], t['road'][0][2])
            # 标记当前正在执行的任务
            self.projectDock.treeWidget.markRunTaskFile(
                self.taskManager.task_step)
            # self.projectDock.treeWidget.markDoneTaskFile(self.taskManager.task_step)
        if msg == "stop":  # 执行当前任务
            logging.info("任务停止...")
            self.motorControlDialog.cmdStopTask()
            self.projectDock.treeWidget.markStopTaskFile(
                self.taskManager.task_step)
        if msg == "process":  # 执行当前任务
            logging.info("任务执行...")
            self.motorControlDialog.cmdRunTask(self.taskManager.task_current)

    def taskData(self, data):
        "测量任务数据处理"
        t1 = MathFunc.hexStrToNeg(data[0:8])
        t2 = MathFunc.hexStrToNeg(data[8:])
        # ad采集饱和溢出, 紧急停止
        if t1 > 60000 or t2 > 60000:
            self.taskManager.stopMove()
            return
        # 刻度系数转换
        t1 = float('%.4f' % (self.baseSetDialog.scale_k *
                             t1 + self.baseSetDialog.scale_b))
        t2 = float('%.4f' % (self.baseSetDialog.scale_k_2 *
                             t2 + self.baseSetDialog.scale_b_2))

        # 获取坐标
        x = self.motorControlDialog.real_x
        y = self.motorControlDialog.real_y
        z = self.motorControlDialog.real_z
        # 任务
        t = self.taskManager.task_current
        # 添加一次数据
        # timetest = time.strftime("%Y:%m:%d-%H:%M:%S", time.localtime())
        if t['ray_type'] == '电子':
            power = t['power'].replace('MV', '').replace('MeV', '')
            if int(power) < 10:
                self.dataTab.add_data(x=x, y=y, z=z, t1=t2, t2=t1)
            else:
                self.dataTab.add_data(x=x, y=y, z=z, t1=t1, t2=t2)
        else:
            self.dataTab.add_data(x=x, y=y, z=z, t1=t1, t2=t2)
        data = self.dataTab.get_datas()
        # return
        # 加速器异常停止
        if len(data) > 2:
            # task_stop_err = self.baseSetWidget.scale_k_2*self.baseSetWidget.task_stop_err+self.baseSetWidget.scale_b_2
            # err = abs(data[-2][-1] - data[-1][-1])
            task_stop_err = self.baseSetDialog.task_stop_err
            if abs(data[-2][-1] - data[-1][-1]) > task_stop_err:
                self.taskManager.stopMove()
                return

        # 曲线显示数据是否实时修正
        if self.baseSetDialog.task_show == "modify":
            x = [float(d[0]) for d in data]
            y = [float(d[1]) for d in data]
            z = [float(d[2]) for d in data]
            tm = [float('%.2f' % float(d[3])) for d in data]
            ts = [float('%.2f' % float(d[4])) for d in data]
            repeat = [float('%.4f' % (m/(s+0.00000001)))
                      for m, s in zip(tm, ts)]
            normal = [float('%.4f' % (100*r/(max(repeat)+0.0000001)))
                      for r in repeat]
            new_data = []
            for i in range(0, len(normal)):
                new_data.append([x[i], y[i], z[i], normal[i], 0])
            data = new_data

        if t['type'] == 'PDD':
            self.signalTunnel.emit([d[2] for d in data], [d[3]
                                                          for d in data], [d[4] for d in data])
        if t['type'] == 'OAR':
            if t['angle'] == '0' or t['angle'] == '180':
                if t['direction'] == 'G->T' or t['direction'] == 'T->G':
                    self.signalTunnel.emit([d[1] for d in data], [
                                           d[3] for d in data], [d[4] for d in data])
                else:
                    self.signalTunnel.emit([d[0] for d in data], [
                                           d[3] for d in data], [d[4] for d in data])
            if t['angle'] == '90' or t['angle'] == '270':
                if t['direction'] == 'G->T' or t['direction'] == 'T->G':
                    self.signalTunnel.emit([d[0] for d in data], [
                                           d[3] for d in data], [d[4] for d in data])
                else:
                    self.signalTunnel.emit([d[1] for d in data], [
                                           d[3] for d in data], [d[4] for d in data])

    def taskStop(self):
        logging.info("删除测量多余的数")
        row = self.dataTab.model.rowCount()
        if row >= 2:
            self.dataTab.model.removeRow(row-1)
            self.dataTab.model.removeRow(row-2)
        else:
            self.dataTab.model.removeRow(0)
        box = QMessageBox(QMessageBox.Information, "警告",
                          "任务执行中断: \r\n1、加速器异常停止\r\n2、剂量率过大，数据溢出\r\n是否继续执行任务?")
        qyes = box.addButton(self.tr("继续执行"), QMessageBox.YesRole)
        qno = box.addButton(self.tr("回原点"), QMessageBox.NoRole)
        qcancel = box.addButton(self.tr("取消"), QMessageBox.NoRole)
        box.exec_()
        if box.clickedButton() == qyes:
            self.taskManager.processMove()
        elif box.clickedButton() == qno:
            self.startTaskAct.setEnabled(True)
            self.motorControlDialog.backZero()
        elif box.clickedButton() == qcancel:
            self.taskManager.clearFlag()
            self.startTaskAct.setEnabled(True)
        else:
            return

    def taskDone(self):
        """ 任务完成一次 """
        # 保存数据
        self.projectDock.treeWidget.addDataFile(
            condition=self.taskManager.task_current, data=self.dataTab.get_datas())
        # 标记当前任务执行完成
        self.projectDock.treeWidget.markDoneTaskFile(
            self.taskManager.task_step)
        if self.taskManager.checkDone():
            #所有任务执行完成
            box = QMessageBox(QMessageBox.Information, "提示",
                              "所有任务已经执行完成!\r\n\r\n是否回到原点?")
            qyes = box.addButton(self.tr("回原点"), QMessageBox.YesRole)
            qcancel = box.addButton(self.tr("取消"), QMessageBox.NoRole)
            box.exec_()
            if box.clickedButton() == qyes:
                self.motorControlDialog.backZero()
                self.startTaskAct.setEnabled(True)
            elif box.clickedButton() == qcancel:
                self.taskManager.clearFlag()
                self.startTaskAct.setEnabled(True)
            else:
                return
        else:
            if self.baseSetDialog.task_auto:
                self.taskManager.nextMove()
            else:
                box = QMessageBox(QMessageBox.Information, "提示", "是否执行下一个任务?")
                qyes = box.addButton(self.tr("执行"), QMessageBox.YesRole)
                qno = box.addButton(self.tr("回原点"), QMessageBox.NoRole)
                qcancel = box.addButton(self.tr("取消"), QMessageBox.NoRole)
                box.exec_()
                if box.clickedButton() == qyes:
                    self.taskManager.nextMove()
                elif box.clickedButton() == qno:
                    self.motorControlDialog.backZero()
                    self.startTaskAct.setEnabled(True)
                elif box.clickedButton() == qcancel:
                    self.taskManager.clearFlag()
                    self.startTaskAct.setEnabled(True)
                else:
                    return


if __name__ == '__main__':
    import sys
    app = QApplication(sys.argv)
    win = MainWindow()
    win.show()
    app.exec_()
